"""
 套接字编程分类:
    流式套接字(SOCK_STREAM):
        以字节流方式传输数据,实现tcp网络传输方案.(面向链接--tcp协议--可靠的--流式套接字)
    数据报 套接字(SOCK_DGRAM):
        以数据报形式传输数据,实现udp网络传输方案.(无连接--udp协议--不可靠--数据报套接字)

    通讯方式:
        服务端 --> 客户端 or 客户端 --> 服务端

    服务端流程:
            socket -->  bind --> listen --> accept          --> send/recv    --> close
    释义: 实例套接字 --> 绑定ip端口--> 监听 --> 阻塞等待客户端连接 --> 消息收发  --> 挂断电话(销毁)
		1.创建套接字 socket:
	        sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, proto=0)
	        功能: 创建套接字
	        参数: socket_family: 网络地址类型, ocket.AF_INET 表示ipv4
				  socket_type: 套接字类型(传输类型), socket.SOCK_STREAM(流式/tcp), socket.SOCK_DGRAM(数据报/udp)
				  proto: 通常为0, 系统层才有子协议, tcp和udp都没有子协议, 所以默认为0

		2. 绑定地址 bind (绑定服务器的ip地址(回环ip地址,局域网ip和外网ip)):
			本地地址: "localhost", '127.0.0.1' 回环地址
			网络地址: '172.168.22.11'   外网ip
			自动获取地址: '0.0.0.0'   局域网ip

			sockfd.bind(addr)
			功能: 绑定本机网络地址
			参数: 二元元组(ip, port)  ('0.0.0.0', 8693(端口号))

		3. 设置监听 listen:
			sockfd.listen(n)
			功能: 将套接字设置为监听套接字, 确定监听队列大小
			参数: 监听队列大小

		4. 等待处理客户端连接请求 accept:
			connfd, addr == sockfd.accept()
			功能: 阻塞等待,处理的客户端请求
			返回值: connfd; 客户端连接套接字
					addr; 连接的客户端地址

		5. 消息收发 send/recv:
			data = connfd.recv(buffersize)
			功能: 接受客户端消息
			参数: 每次最多接受消息的大小
			返回值: 接收到的内容

			n = connfd.send(data)
			功能: 发送消息
			参数: 要发送的内容 bytes格式(字节)
			返回值: 发送的字节数

		6. 关闭套接字 close:
			sockfd.close()
			功能: 关闭套接字(销毁网络服务)

"""

import socket

sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # ipv4, tcp模式
sockfd.bind(("127.0.0.1", 8693))    # 绑定地址
sockfd.listen(50)                   # 设置监听

# <editor-fold desc="处理当前链接">
def method_server():
	"""服务器接受新的链接"""
	while True:
		print("等待连接中...")

		try:                                # 如果ctrl + c 退出服务,会报异常,所以处理一下异常,不让服务轻易退出
			connfd, addr = sockfd.accept()  # 阻塞等待 处理链接请求
			print(f"客户端地址为: {addr}")
		except KeyboardInterrupt:
			print("服务器主动退出!")
			break
		except Exception as e:
			print("遇到了其他错误: ", e)
			continue

		current_client(connfd)              # 转当前客户端的链接

def current_client(connfd):
	"""处理当前客户端的链接"""
	while True:
		data = connfd.recv(1024)  # 收取消息
		if not data:
			print(f"客户端已断开链接,没有收到任何消息: {data}")
			connfd.close()  # 关闭客户端的套接字
			break
		print(f"收到客户端消息: {data.decode()}")
		date = input("给客户端发送消息: ")
		data = f"""HTTP/1.1 200 ok
		Content-Type:text/html
		
		<h1>{date}</h1>
		"""
		n = connfd.send(data.encode())  # 发送消息,必须是字节串
		print(f"发送了{n}字节.")




# </editor-fold>

method_server()

sockfd.close()                              # 关闭服务器的套接字
